import sc_models
import utils
from django.utils import simplejson
from django.http import HttpResponse, HttpResponseServerError, HttpResponseForbidden
from django.core.exceptions import PermissionDenied

import signals


def fix_request_method(request):
    if request.method == 'PUT' or request.POST.get('_method')=='PUT':
        request.method = 'POST'
        request._load_post_and_files()
        request.method = 'PUT'
        request.PUT = request.POST
        del request._post
    # handle DELETE
    return request

class AlreadyRegistered(Exception):
    pass

class NotRegistered(Exception):
    pass

class InvalidScModel(Exception):
    pass

class SproutcoreApi(object):
    """
    A SproutcoreApi object encapsulates an instance of the Django-Sproutcore API
    """
    def __init__(self):
        self._registry = {} # Model identifier -> SproutcoreModel and SproutcoreModelManager
    
    def register(self, sc_model_class, sc_model_manager_class=None, app_name=None, model_name=None):
        """
        Registers a given Sproutcore Model with either the default Manager or a custom manager.
        app_name and model_name must be unique. If they are not provided, they are automatically
        evaluated by introspection.
        """
        if not sc_model_manager_class:
            sc_model_manager_class = sc_models.ScModelManager
        
        if not issubclass(sc_model_class, sc_models.ScModel):
            raise InvalidScModel('sc_model must be a subclass of ScModel')
        if not app_name:
            app_name = sc_model_class.__module__.split('.')[-2]
        if not model_name:
            model_name = utils.camelcase_to_underscore(sc_model_class.__name__)
        
        identifier = "%s.%s" % (app_name, model_name)
        
        if identifier in self._registry:
            raise AlreadyRegistered('%s is already registered' % identifier)
        
        self._registry[identifier] = sc_model_manager_class(sc_model_class, self)
        
    def get_manager(self, app_name, model_name):
        return self._registry["%s.%s" % (app_name, model_name)]
    
    def handle_request(self, request, app_name, model_name, obj_id=None):
        try:
            request = fix_request_method(request)
            signals.sc_incoming_request.send(sender=self, request=request, app_name=app_name, model_name=model_name, obj_id=obj_id)
            user = request.user
            # normalize ids
            ids=None
            ids_string = request.GET.get('ids', None)
            if obj_id:  #this is a single object action
                ids = [obj_id,]
            elif ids_string: # this is a multi object action
                ids = ids_string.split(',')
            else:
                # there are no ids
                pass
            
            # load the manager instance
            manager = self.get_manager(app_name, model_name)
            errors = []
            result = None
            if request.method == 'GET':
                if ids:
                    #refreshRecords
                    result = manager.show(ids,user=user)
                elif request.GET.has_key('action'):
                    #special custom action
                    action = request.GET.get('action', None)
                    if hasattr(manager, action):
                        # TODO: add check for registered custom actions (security)
                        #print 'has action'
                        result = getattr(manager,action)(query_parameters=request.GET, user=user)
                else:
                    #listFor
                    result = manager.list(request.GET, user=user)
            elif request.method == 'PUT':
                # commitRecords
                #print "PUT records: %s" % request.PUT.get('records')
                data = simplejson.loads( request.PUT.get('records') )
                #print data
                result = manager.update(data,user=user)
            elif request.method == 'POST':
                # createRecords
                #print "POST records: %s" % request.POST.get('records')
                data = simplejson.loads( request.POST.get('records') )
                result = manager.create(data,user=user)
            elif request.method == 'DELETE':
                #print 'going to delete %s' % ids
                result = manager.destroy(ids,user=user)
            else:
                # raise illigal request error
                pass
            
            json = simplejson.dumps(result)
            return HttpResponse(json, mimetype='application/json')
        except PermissionDenied, e:
            #print u'PermissionDenied: %s' % (e,)
            return HttpResponseForbidden(e)
            
api = SproutcoreApi()
        